docker现在已经支持构建多cpu架构images,这里我们将一步步的实现arm64和amd64架构的docker images
Multi architecture Docker Image
Docker image 存储设计之初,没有充分考虑到镜像Multi architecture的支持,而是简单的使用镜像存储库的前缀来区分相同应用的不同平台,并建议开发者将不同平台的镜像应该push到相对应的Docker hub的镜像仓库中,目前这种设计依旧保存在最新的Docker设计文档中:
https://github.com/docker-library/official-images#architectures-other-than-amd64
我们可以基于镜像存储库的前缀,或者是基于tag或image名称后缀来区分不同的运行平台来pull相应的Docker镜像,例如:
1 | arm32v7 variant |
不过这对用户来说是不友好的设计,而好的设计是应该用户只要执行docker pull myapp就行了而不用关心容器的运行平台,Docker engine根据运行环境来pull相关的镜像,真正的做到 “Run Any App, Anywhere”。
Docker社区早就注意到了这个问题,并通过重新定义 v2.2 Image specification format(PR #1068)并在 Implement schema2 manifest formats(PR #1281)实现了Multi architecture Docker镜像功能。从Docker registry v2.3和Docker 1.10 开始,Docker hub就可以pull multi architecture Docker镜像了。
那么,我们就run相同的命令 “docker run -it –rm busybox arch” 在不同CPU architecture的host都得到了正确的运行结果,这是用户体验的一个极大的提升,用户根本不用关心 image的CPU arch 和OS的类型了。
分析
自从Docker registry v2.3和Docker 1.10开始,Docker通过支持新的image Media 类型 manifest list 实现了Multi architecture Docker镜像功能:
- 一个image manifest list 包含指向已经存在镜像的manifest对象列表
- 一个image manifest list包含已经存在镜像的manifest对象的平台特性(CPU arch和OS类型)特征
1 | "platform": { |
- 根据manifest list对象定义,我们可以通过下面的流程了解Docker是如何支持Multi architecture Docker镜像
实践
准备
这里实现一个 arm或者amd64 平台都可以执行的main.go脚本
1 | package main |
构建镜像
虽然我们要实现 “多架构” 构建,但我们首先构建这两个架构的image。
Dockerfile-amd64,使用它构建 amd64 版本(注意GOARCH = amd64)。1
2
3
4
5
6
7
8
9
10
11
12
13FROM golang:1.11.1-alpine as build
RUN apk add --update --no-cache ca-certificates git
RUN mkdir /app
WORKDIR /app
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags="-w -s" -o /go/bin/app
FROM scratch
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=build /go/bin/app /go/bin/app
ENTRYPOINT ["/go/bin/app"]
构建镜像1
# docker build -f Dockerfile-amd64 -t liupeng0518/test-arch:amd64 .
推送
1 | docker push liupeng0518/test-arch:amd64 |
接下来构建arm版本(注意GOARCH=arm),Dockerfile-arm
1 | FROM golang:1.11.1-alpine as build |
构建镜像1
# docker build -f Dockerfile-arm -t liupeng0518/test-arch:arm .
推送
1 | # docker push liupeng0518/test-arch:arm |
本地run测试:
1 | # docker run -it liupeng0518/test-arch:arm |
Multi-Architecture Manifest
这里开启docker Experimental:
server:1
2
3{
"experimental" : true,
}
client:1
2
3
4
5
6
7
8
9
10
11➜ sudo cat /etc/docker/daemon.json
{
"experimental" : true,
"registry-mirrors": ["https://uibirsz0.mirror.aliyuncs.com"],"graph":"/home/.docker-graph"
}
➜ test cat ~/.docker/config.json
{
...
"experimental": "enabled"
...
}
使用docker verison查看是否开启。
确保镜像推送至仓库后,我们现在可以创建multi-architecture manifest
1 | ➜ docker manifest create liupeng0518/test-arch liupeng0518/test-arch:arm liupeng0518/test-arch:amd64 --amend |
这里,第一个参数liupeng0518/test-arch是我们的多架构清单的名称。剩下的参数是我们想要包含的images。
理论上讲这样就ok,如果我们使用架构特定的基础图像,那么一切都会好的。我们应该使用与架构无关的 scratch 镜像。 我们来看一下multi-architecture image的问题:
1 | ➜ docker manifest inspect docker.io/liupeng0518/test-arch:latest |
1 | { |
此清单中,如果有问题可以如下命令修复:1
➜ docker manifest annotate --arch arm liupeng0518/test-arch liupeng0518/test-arch:arm
推送镜像1
➜ docker manifest push docker.io/liupeng0518/test-arch:latest
我们来测试下我们构建的镜像:
amd64:
1 | ➜ docker run -it liupeng0518/test-arch |
arm64
`
docker run -it liupeng0518/test-arch
Unable to find image ‘liupeng0518/test-arch:latest’ locally
latest: Pulling from liupeng0518/test-arch
Digest: sha256:c411f59f30210801e7f0921cb9350455f66ef67a23175bd136fddb4663afa0f6
Status: Downloaded newer image for liupeng0518/test-arch:latest
Hello, 世界!
GOOS: linux
GOARCH arm
`